import { Engine } from "../../../Engine";
import { color } from "../../../core/color";
import { any } from "../../../core/logic";
import { Pass } from "../Pass";
import { Effect, EffectType } from "./Effect";
import { vignette_frag } from "./shaders/vignette_frag";
import { vignette_vert } from "./shaders/vignette_vert";
/**
 * 电影镜头特效
 * @class
 * @extends w.effects.Effect
 * @memberof w.effects
 */
class Vignette extends Effect {
    /**
     * @constructor
     * @param {*} opts 
     * @param {String}opts.blackColor 【可选,缺省:"#000000"】镜头周围黑化颜色。
     * @param {Number}opts.intensity 【可选,缺省:1.0】镜头周围黑化强度。
     * @param {Array}opts.center 【可选,缺省:[0.5,0.5]】镜头周围黑化的中心点。
     * @param {Number}opts.smothness 【可选,缺省:1.0】镜头周围黑化平滑程度。
     */
    constructor(opts = {}) {
        super(opts);
        this.type=EffectType.Vignette;
        this.sampler = Engine.instance.device.createSampler({
            magFilter: 'linear',//nearest linear
            minFilter: 'linear'
        });
        this.initBuffer();
        this.initPipeLine();
        this.blackColor=any(opts.blackColor,"#000000");
        this.intensity=any(opts.intensity,1.0);
        this.center=any(opts.center,[0.5,0.5]);
        this.smothness=any(opts.smothness,1.0);
        //初始化参数
        this.autoUpdate=true;
        this.update();
    }
    set blackColor(v){
        this._blackColor = v;
        let buffer=color.format(v,false);
        Engine.instance.queue.writeBuffer(
            this.vignetteBuffer,
            0,
            buffer
        );
        buffer=null;
        this.update();
    }
    get blackColor(){
        return this._blackColor;
    }
    set intensity(v){
        this._intensity = v;
        let buffer=new Float32Array([v]);
        Engine.instance.queue.writeBuffer(
            this.vignetteBuffer,
            12,
            buffer
        );
        buffer=null;
        this.update();
    }
    get intensity(){
        return this._intensity;
    }
    set center(v){
        this._center = v;
        let buffer=new Float32Array(v);
        Engine.instance.queue.writeBuffer(
            this.vignetteBuffer,
            16,
            buffer
        );
        buffer=null;
        this.update();
    }
    get center(){
        return this._center;
    }
    set smothness(v){
        this._smothness = v;
        let buffer=new Float32Array([v]);
        Engine.instance.queue.writeBuffer(
            this.vignetteBuffer,
            24,
            buffer
        );
        buffer=null;
        this.update();
    }
    get smothness(){
        return this._smothness;
    }
    
    initBuffer() {
        this.vignetteBuffer = Engine.instance.device.createBuffer({
            label: "vignetteBuffer",
            size: 32,
            usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
        });
    }
    initPipeLine() {
        this.bindGroupLayout = Engine.instance.device.createBindGroupLayout({
            label: "layout",
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.FRAGMENT,
                    sampler: {
                        type: "filtering"
                    },
                },
                {
                    binding: 1,
                    visibility: GPUShaderStage.FRAGMENT,
                    texture: {
                        sampleType: "float",
                        viewDimension: "2d",
                        multisampled: false
                    }
                },{
                    binding: 2,
                    visibility: GPUShaderStage.FRAGMENT,
                    buffer: {
                        type: "uniform"
                    },
                }
                ]
        });
        let pipeLayout = Engine.instance.device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] });
        this.pipeLine = Engine.instance.device.createRenderPipeline({
            label: 'Fog Pipline',
            layout: pipeLayout,
            vertex: {
                module: Engine.instance.device.createShaderModule({
                    code: vignette_vert,
                }),
                entryPoint: 'main'
            },
            fragment: {
                module: Engine.instance.device.createShaderModule({
                    code: vignette_frag,
                }),
                entryPoint: 'main',
                targets: [
                    {
                        format: Engine.instance.format
                    }
                ]
            },
            primitive: {
                topology: 'triangle-list',
                cullMode: 'back',
                frontFace: 'ccw'
            }
        });
    }
    initBindGroup(texture) {
        if(this.group && this.group.id!=texture.id){
            this.group=null;
        }
        if(!this.group){
            this.group=Engine.instance.device.createBindGroup({
                label: 'Texture Group with Texture/Sampler',
                layout: this.bindGroupLayout,
                entries: [
                    {
                        binding: 0,
                        resource: this.sampler
                    },
                    {
                        binding: 1,
                        resource: texture.view
                    },
                    {
                        binding: 2,
                        resource: {
                            buffer: this.vignetteBuffer,
                            size: 32,
                        }
                    }
                ]
            });
            this.group.id=texture.id;
        }
        return this.group

    }
    onRender(commandEncoder) {
        //执行帧渲染
        const pass = super.onRender(commandEncoder);
        const texture = Pass.instance().readAttach;
        const renderPass = commandEncoder.beginRenderPass(pass);
        renderPass.setPipeline(this.pipeLine);
        let bindGroup = this.initBindGroup(texture);
        // set uniformGroup
        renderPass.setBindGroup(0, bindGroup)
        renderPass.draw(3)
        renderPass.end()
    }
    getDescript() {
        if (this._descript) {
            if (this._descript.size[0] !== Engine.instance.size[0] || this._descript.size[1] !== Engine.instance.size[1]) {
                this._descript = null;
            }else{
                this._descript.colorAttachments[0].view=Pass.instance().writeAttach.view;
            }
        }
        if (!this._descript) {
            this._descript = {
                colorAttachments: [
                    {
                        view: Pass.instance().writeAttach.view,
                        loadOp: 'clear',
                        clearValue: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
                        storeOp: 'store',
                    }
                ]
            }
            this._descript.size = Engine.instance.size;
        }
        return this._descript;
    }
}
export { Vignette }